<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>数据属性描述符</title>
  <!-- 
  在JavaScript中，数据属性描述符（Data Property Descriptor）用于定义对象的属性，并控制这些属性的行为。每个数据属性描述符都可以包含多个特性，这些特性决定了该属性的可操作性。以下是关于数据属性描述符的总结说明：
  一、数据属性描述符的组成
  数据属性描述符主要有以下四个特性：
  1. value：
    - 属性的值，可以是任何有效的JavaScript值（包括对象、数组、函数等）。

  2. writable：
    - 一个布尔值，指示属性的值是否可以被修改。如果为 `true` ，则可以修改；如果为 `false` ，则不可修改。

  3. enumerable：
    - 一个布尔值，指示属性是否可以在 `for...in` 循环中被枚举。如果为 `true` ，则该属性会出现在对象的枚举属性列表中；如果为 `false` ，则不会。

  4. configurable：
    - 一个布尔值，指示属性是否可以被删除或修改其特性。如果为 `true` ，则可以删除该属性或修改其特性（如 `writable` 、 `enumerable` 和 `configurable` ）；如果为 `false` ，则不可修改。

  二、创建数据属性描述符
  可以使用 `Object.defineProperty()` 方法来创建或修改对象的属性描述符。该方法接受三个参数：目标对象、属性名和属性描述符对象。
  const obj = {};

  // 定义一个属性
  Object.defineProperty(obj, 'name', {
      value: 'Alice',
      writable: true,      // 可写
      enumerable: true,    // 可枚举
      configurable: true   // 可配置
  });

  console.log(obj.name); // 输出: Alice

  // 修改属性值
  obj.name = 'Bob';
  console.log(obj.name); // 输出: Bob

  // 删除属性
  delete obj.name;
  console.log(obj.name); // 输出: undefined
  三、只读属性
  可以通过将 `writable` 设置为 `false` 来创建只读属性。
  const obj = {};

  Object.defineProperty(obj, 'age', {
      value: 30,
      writable: false,    // 不可写
      enumerable: true,
      configurable: true
  });

  console.log(obj.age); // 输出: 30

  // 尝试修改属性值
  obj.age = 35; 
  console.log(obj.age); // 输出: 30 (未修改)

  四、不可枚举属性
  可以通过将 `enumerable` 设置为 `false` 来创建不可枚举的属性。
  const obj = {};

  Object.defineProperty(obj, 'hidden', {
      value: 'secret',
      enumerable: false,  // 不可枚举
      configurable: true
  });

  console.log(obj.hidden); // 输出: secret

  // 使用Object.keys()获取可枚举属性
  console.log(Object.keys(obj)); // 输出: [] (没有返回hidden属性)
  五、不可配置属性
  可以通过将 `configurable` 设置为 `false` 来创建不可配置的属性。
  const obj = {};

  Object.defineProperty(obj, 'constant', {
      value: 100,
      writable: false,
      enumerable: true,
      configurable: false // 不可配置
  });

  // 尝试删除属性
  delete obj.constant; // 删除失败
  console.log(obj.constant); // 输出: 100

  // 尝试修改属性特性
  Object.defineProperty(obj, 'constant', {
      writable: true // 报错: TypeError: Cannot redefine property: constant
  });
  六、总结
  - 数据属性描述符用于定义对象属性的行为，包括值、可写性、可枚举性和可配置性。
  - 可以通过 `Object.defineProperty()` 方法创建或修改属性描述符。
  - 理解数据属性描述符有助于更好地控制对象的属性，增强代码的安全性和可维护性。
   -->
</head>
<body>

  <script>
    // 1. 数据属性描述符
    // 数据属性描述符用于定义对象属性的行为，包括值、可写性、可枚举性和可配置性。
    // 可以通过 `Object.defineProperty()` 方法创建或修改属性描述符。
    const obj = {
      name: 'John',
      age: 30
    };

    Object.defineProperty(obj, 'name', {
      value: 'Alice', // 返回这个value
      writable: false, // 不可写   obj对象的name属性不写入(只读属性 readonly)
      enumerable: false, // 可枚举  obj对象的name属性不可枚举(for in/Object.keys)
      configurable: false // 可配置 obj对象的name属性不可以被删除
    })

    delete obj.name; // 删除失败
    console.log(obj.name); // 输出: Alice

    // 通过Object.defineProperty添加一个新的属性
    Object.defineProperty(obj, "address", {})
    delete obj.address
    console.log(obj)

    console.log(Object.keys(obj))

    obj.name = "kobe"
    console.log(obj.name)
    
    
  </script>
  
</body>
</html>